defmodule Pango.DeeprInfo do
	@moduledoc false


	import UserLib
	require Logger

	def info(user, args, caller_mod, func) do
		{repo, sql, pg_param, cypher, cypher_params, obj_keys, query_result} =
			Pango.DeeprParse.parse_query(args, user, func, caller_mod)
		result = psql_execute(sql, repo, user, pg_param, obj_keys, caller_mod, query_result, args)
		result = cypher_execute(cypher, cypher_params, result, user, obj_keys, caller_mod, args)
		Enum.reduce(
			args,
			result,
			fn ({obj, _}, acc) ->
				case Map.get(acc, obj) do
					nil ->
						Map.put(acc, obj, nil)
					v ->
						acc
				end
			end
		)
	end

	def psql_execute(:first, _repo, _user, _pg_param, _obj_keys, _, query_result, _) do
		query_result
	end
	def psql_execute(sql, {m, f, a}, user, pg_param, obj_keys, caller_mod, query_result, args) do
		case apply(m, f, [sql, pg_param]) do
			{:ok, %{rows: rows}} ->
				rows
			{:error, reason} ->
				Logger.error("Deepr Info Pg Execute Error, reason: #{inspect(reason)}")
				[]
			rows ->
				rows
			err ->
				Logger.error("Deepr Info Pg Execute Error, reason: #{inspect(err)}")
				[]
		end
		|> Enum.reduce(
				 query_result,
				 fn ([object, method, rows], acc) ->
					 mod = caller_mod.get_db_mod(object)
					 row = case rows do
						 [h | _] when h != nil ->
							 DeeprHelpLib.match(
								 caller_mod,
								 user,
								 [h],
								 Pango.DeeprList.get_rel(mod, object, args, "optional"),
								 Pango.DeeprList.get_rel(mod, object, args, "match"),
								 mod.foreign()
							 )
							 |> hd()
						 _ ->
							 nil
					 end
					 row = case row != nil && Map.get(mod.pipelines(), "info") do
						 {m, f, a} ->
							 apply(m, f, [:after, user, object, row | a])
						 _ ->
							 row
					 end
					 row = if row != nil do
						 [row | _] = DeeprHelpLib.guard([row], mod, MapLib.get_in(args, [object, "=>"]))
						 row
					 else
						 row
					 end
					 Map.put(acc, object, row)
				 end
			 )
	end

	def cypher_execute(:first, _cypher_params, result, _, _obj_keys, _, _) do
		result
	end
	def cypher_execute(cypher, cypher_params, result, user, _obj_keys, caller_mod, args) do
		cypher
		|> IO.iodata_to_binary()
		|> Neo4jDb.get_one(cypher_params)
		|> case do
				 %{"entry" => entry, "object" => object} ->
					 mod = caller_mod.get_db_mod(object)
					 [entry | _] = DeeprHelpLib.match(
						 caller_mod,
						 user,
						 [entry],
						 Pango.DeeprList.get_rel(mod, object, args, "optional"),
						 Pango.DeeprList.get_rel(mod, object, args, "match"),
						 mod.foreign()
					 )
					 row = case Map.get(mod.pipelines(), "info") do
						 {m, f, a} ->
							 apply(m, f, [:after, user, object, entry | a])
						 _ ->
							 entry
					 end
					 [entry | _] = DeeprHelpLib.guard([row], mod, Pango.DeeprList.get_select(object, args))
					 Map.put(result, object, entry)
				 _ ->
					 result
			 end
	end


end
